package com.linktrip.devicemanager.websocket.product;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ExecutionException;

import com.alibaba.fastjson.JSONObject;
import com.linktrip.devicemanager.async.CallbackTaskService;
import com.linktrip.devicemanager.async.LogTaskService;
import com.linktrip.devicemanager.entity.DeviceInfo;
import com.linktrip.devicemanager.entity.DeviceLog;
import com.linktrip.devicemanager.entity.Upgrade;
import com.linktrip.devicemanager.server.DeviceLogService;
import com.linktrip.devicemanager.sms.SMSConfig;
import com.linktrip.devicemanager.task.DeviceInfoTask;
import com.linktrip.devicemanager.task.IsNeedUpgradeTask;
import com.linktrip.devicemanager.task.UpgradeInfoTask;
import com.linktrip.devicemanager.util.ByteUtil;
import com.linktrip.devicemanager.util.CRC8Util;
import com.linktrip.devicemanager.util.CommandUtil;
import com.linktrip.devicemanager.util.DataAnalysis;
import com.linktrip.devicemanager.util.FileUtil;
import com.linktrip.devicemanager.util.HttpUtil;
import com.linktrip.devicemanager.util.SpringContextUtil;
import com.linktrip.devicemanager.util.ToolKits;
import com.linktrip.devicemanager.websocket.entity.DataStruct;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;

public class LogicServerHandler extends ChannelInboundHandlerAdapter {
	Logger log = LoggerFactory.getLogger(LogicServerHandler.class);
	private DataAnalysis analysis = new DataAnalysis();
	private boolean isFirst = false;
	ExecutorService executor = Executors.newFixedThreadPool(10);
	String deviceNo = "";// 设备标识
	DeviceInfo deviceInfo = null;
	DeviceLogService deviceLogService =	SpringContextUtil.getBean("deviceLogService");
	LogTaskService logTaskService = SpringContextUtil.getBean("logTaskService");
	CallbackTaskService callbackTaskService = SpringContextUtil.getBean("callbackTaskService");

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		// TODO Auto-generated method stub
		super.channelActive(ctx);
		isFirst = true;
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		// TODO Auto-generated method stub
		if (null != executor) {
			executor.shutdown();
			executor = null;
			ToolKits.removeDeviceFromList(deviceNo);
			ToolKits.removeMessageFromMap(deviceNo);
			log.info("channelInactive");
		}
		if (null != analysis)
			analysis = null;
		super.channelInactive(ctx);
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) { // 2
			IdleStateEvent event = (IdleStateEvent) evt;
			if ((event.state() == IdleState.READER_IDLE) || (event.state() == IdleState.WRITER_IDLE)
					|| (event.state() == IdleState.ALL_IDLE)) {
				ctx.close();
				ToolKits.removeDeviceFromList(deviceNo);
				ToolKits.removeMessageFromMap(deviceNo);
				log.warn("{} 超时类型：{}", ctx.channel().remoteAddress(), event.state());
			}

		} else {
			super.userEventTriggered(ctx, evt);
		}
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		// TODO Auto-generated method stub
		// super.channelRead(ctx, msg);
		ByteBuf bf = (ByteBuf) msg;

		byte[] datas = new byte[bf.readableBytes()];
		bf.readBytes(datas);
		//StringBuilder sb = new StringBuilder();
		if (datas.length < 2){
			ReferenceCountUtil.release(bf);
			if(null != ctx)ctx.close();
			return;
		}

		int len = datas[1] + datas[0];

		if (len < 54) {
			ReferenceCountUtil.release(bf);
			if(null != ctx)ctx.close();
			return;
		}

		byte[] data = new byte[datas.length - 2];
		System.arraycopy(datas, 2, data, 0, data.length);
		String byteString = ByteUtil.bytes2String(datas);
		log.info("channelRead===>[from]:{}",byteString);
		byteString = null;
		byte[] veri = new byte[53];
		System.arraycopy(data, 0, veri, 0, veri.length);
		if (!CRC8Util.isVerify(veri, data[53])) {
			log.warn("crc verify is wrong !!!");
			ReferenceCountUtil.release(msg);
			veri = null;
			if(null != ctx)ctx.close();
			return;
		}
		veri = null;
		deviceNo = analysis.getDeviceId(data);
		deviceInfo = getDeviceInfo(deviceNo);
		if (null == deviceInfo) {
			ReferenceCountUtil.release(msg);
			if(null != ctx)ctx.close();
			log.warn("[deviceId {} is not validate]", deviceNo);
			return;
		}
		ToolKits.putDeviceSocketIntoMap(deviceNo, ctx);

		DataStruct ds = analysis.analysisAll(data);
		DeviceLog entity = analysis.getDeviceLog(ds);
		entity.setCreate_date(System.currentTimeMillis());

		if (ds.getType() == CommandUtil.BYTE_REQUEST) {

			DataStruct content = CommandUtil.getUnlockCommand(0, 0, 0);
			content.setMessageId((short) entity.getMessage_id());
			content.setType(CommandUtil.BYTE_RESPONSE);
			CommandUtil.sendCommand(ctx, content.toByteArray());

			if (isFirst) {
				Upgrade up = isNeedUpgrade(deviceInfo.getId(), entity.getSys_version(), entity.getHdware_version());
				if (up != null) {
					content.setMessageId(CommandUtil.getSequence());
					content.setType(CommandUtil.BYTE_UPGRADE_REQUEST);
					content.setSysVersion(up.getSwVersion());
					content.setHdwareVer(up.getSwHwVersion());
					content.setLength(54 + 2 + 2);
					content.setSegmentId((short) 0);
					content.setSegmentCount((short) up.getTotal());
					CommandUtil.sendCommand(ctx, content.toByteArray());
				}
			}

			isFirst = false;

		} else if (ds.getType() == CommandUtil.BYTE_UPGRADE_REQUEST) {
			Upgrade up = isUpgrade(deviceInfo.getId(), entity.getSys_version(), entity.getHdware_version());
			if (null != up) {
				byte[] upgradeData = FileUtil
						.file2Bytes(up.getTargetPath() + up.getSwName() + ds.getSegmentId());
				DataStruct content = CommandUtil.getUnlockCommand(0, 0, 0);
				content.setType(CommandUtil.BYTE_UPGRADE_RESPONSE);
				content.setSysVersion(ds.getSysVersion());
				content.setHdwareVer(ds.getHdwareVer());
				if (null != upgradeData) {
					content.setSegmentCount((short) up.getTotal());
					content.setSegmentId(ds.getSegmentId());
					short btLen = (short) (54 + 2 + 2 + upgradeData.length + 4);
					content.setLength(btLen);
					CommandUtil.sendCommand(ctx, content.toByteArray(upgradeData));
				} else {
					content.setSegmentCount((short) 0);
					content.setSegmentId((short) 0);
					short btLen = (short) (54 + 2 + 2);
					content.setLength(btLen);
					CommandUtil.sendCommand(ctx, content.toByteArray());
				}
			} else {
				DataStruct content = CommandUtil.getUnlockCommand(0, 0, 0);
				content.setType(CommandUtil.BYTE_UPGRADE_RESPONSE);
				content.setMessageId(ds.getMessageId());
				content.setSegmentCount((short) 0);
				content.setSegmentId((short) 0);
				content.setSysVersion(ds.getSysVersion());
				content.setHdwareVer(ds.getHdwareVer());
				short btLen = (short) (54 + 2 + 2);
				content.setLength(btLen);
				CommandUtil.sendCommand(ctx, content.toByteArray());
			}
		}

		if (entity.getLock_status() == 1 || entity.getLock_status() == 2) {
			DeviceInfo info = new DeviceInfo();
			info.setStatus(entity.getLock_status());
			info.setDevice_no(entity.getDevice_no());
			info.setLatitude(entity.getLatitude());
			info.setLongitude(entity.getLongitude());
			info.setCreate_date(entity.getCreate_date());
			// info.setLocationFlag(entity.getLocationFlag());//定位类型 1:GPS 2:LBS
			//dataCallback(info);// callback
			callbackTaskService.dataCallback(info);
			ToolKits.addMessageIntoMap(deviceNo, entity.getLock_status());
		}

		// 更新数据到数据库
		//deviceLogService.addDeviceLog(entity);// 存入数据库
		logTaskService.saveLog(entity);
		//ReferenceCountUtil.release(msg);//释放计数器
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		// TODO Auto-generated method stub
		try {
			super.exceptionCaught(ctx, cause);
		} catch (Exception e) {
			log.error("Exception:{}", e.getMessage());
		}
		
		isFirst = false;
		log.warn("exceptionCaught===>isFirst:{}", isFirst);
	}

	public Upgrade isNeedUpgrade(int deviceId, int swVersion, int hwVersion) {
		IsNeedUpgradeTask isNeedUpgradeTask = new IsNeedUpgradeTask(deviceId, swVersion, hwVersion);
		FutureTask<Upgrade> future = new FutureTask<Upgrade>(isNeedUpgradeTask);
		executor.submit(future);

		try {
			return future.get();
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
			return null;
		}
	}

	public Upgrade isUpgrade(int deviceId, int swVersion, int hwVersion) {
		UpgradeInfoTask upgradeInfoTask = new UpgradeInfoTask(deviceId, swVersion, hwVersion);
		FutureTask<Upgrade> future = new FutureTask<Upgrade>(upgradeInfoTask);
		executor.submit(future);

		try {
			return future.get();
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
		return null;
	}

	public DeviceInfo getDeviceInfo(String deviceNo) {
		if (ToolKits.isEmpty(deviceNo))
			return null;
		DeviceInfo info = null;
		info = ToolKits.getDeviceInfo(deviceNo);
		if (info != null)
			return info;
		DeviceInfoTask deviceInfoTask = new DeviceInfoTask(deviceNo);
		FutureTask<DeviceInfo> future = new FutureTask<DeviceInfo>(deviceInfoTask);
		executor.submit(future);

		try {
			info = future.get();
			if (null != info) {
				ToolKits.addDeviceInfo(info.getDevice_no(), info);
			}
			return info;
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
			return null;
		}
	}
	
//	public static void main(String[] args) {
//		DataStruct content = CommandUtil.getUnlockCommand(0, 0, 0);
//		content.setMessageId((short) 0x01);
//		content.setType(CommandUtil.BYTE_RESPONSE);
//		ByteUtil.loggerBytes(content.toByteArray());
//	}

}
